home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Utilities / AltPoly.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  17.8 KB  |  885 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        AltPoly.cpp
  3.  
  4.     Contains:    OpenDoc polygon: optional C++ savvy classes
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     To Do:
  11.                   
  12.         Improve the equality tests for contours and polygons. See comments
  13.         in the two "operator==" methods for details.
  14.     
  15.     In Progress:
  16.         
  17. */
  18.  
  19.  
  20. #ifndef _ALTPOINT_
  21. #include "AltPoint.h"            // Use C++ savvy ODPoint and ODRect
  22. #endif
  23.  
  24. #ifndef _ALTPOLY_
  25. #include "AltPoly.h"
  26. #endif
  27.  
  28. #ifndef SOM_ODTransform_xh
  29. #include "Trnsform.xh"
  30. #endif
  31.  
  32. #ifndef _LINEOPS_
  33. #include "LineOps.h"
  34. #endif
  35.  
  36. #ifndef _ODMEMORY_
  37. #include "ODMemory.h"
  38. #endif
  39.  
  40. #ifndef _EXCEPT_
  41. #include "Except.h"
  42. #endif
  43.  
  44. #ifndef SOM_ODStorageUnit_xh
  45. #include "StorageU.xh"
  46. #endif
  47.  
  48. #ifndef _STDTYPES_
  49. #include "StdTypes.xh"
  50. #endif
  51.  
  52. #ifndef _EXCEPT_
  53. #include "Except.h"
  54. #endif
  55.  
  56. #ifndef _ODDEBUG_
  57. #include "ODDebug.h"
  58. #endif
  59.  
  60. #ifndef _STORUTIL_
  61. #include <StorUtil.h>
  62. #endif
  63.  
  64. #ifndef _STDTYPIO_
  65. #include <StdTypIO.h>
  66. #endif
  67.  
  68. #ifndef _UTILERRS_
  69. #include "UtilErrs.h"
  70. #endif
  71.  
  72. #ifdef _PLATFORM_MACINTOSH_
  73.     #ifndef __GXERRORS__
  74.     #include "GXErrors.h"
  75.     #endif
  76.     #ifndef __GXGRAPHICS__
  77.     #include "GXGraphics.h"
  78.     #endif
  79. #endif
  80.  
  81. #include <stddef.h>                    // Defines offsetof() macro
  82.  
  83. #ifndef _ODDEBUG_
  84. #include "ODDebug.h"
  85. #endif
  86.  
  87.  
  88. const ODSLong kMaxLong    = 0x7FFFFFFF;
  89.  
  90. #pragma segment ODShape
  91.  
  92.  
  93. //==============================================================================
  94. // Destructos
  95. //==============================================================================
  96.  
  97.  
  98. ODTempPolygon::ODTempPolygon( )
  99. {
  100.     // This constructor doesn't do anything special, but if not declared it will
  101.     // be inlined at the call site, resulting in lots of extra code due to the
  102.     // multiple inheritance.
  103. }
  104.  
  105.  
  106. ODTempPolygon::~ODTempPolygon( )
  107. {
  108.     this->Clear();
  109. }
  110.  
  111.  
  112. ODTempPolygonPtr::ODTempPolygonPtr( )
  113.     :fPoly(kODNULL)
  114. {
  115. }
  116.  
  117.  
  118. ODTempPolygonPtr::ODTempPolygonPtr( ODPolygon *p )
  119.     :fPoly(p)
  120. {
  121. }
  122.  
  123.  
  124. ODTempPolygonPtr::~ODTempPolygonPtr( )
  125. {
  126.     delete fPoly;
  127.     fPoly = kODNULL;
  128. }
  129.  
  130.  
  131. TempGXShape::TempGXShape( )
  132.     :fShape(kODNULL)
  133. {
  134. }
  135.  
  136.  
  137. TempGXShape::TempGXShape( gxShape s )
  138.     :fShape(s)
  139. {
  140. }
  141.  
  142.  
  143. TempGXShape::~TempGXShape( )
  144. {
  145.     if( fShape ) {
  146.         GXDisposeShape(fShape);
  147.         fShape = kODNULL;
  148.     }
  149. }
  150.  
  151.  
  152. //==============================================================================
  153. // QuickDraw GX Utilities
  154. //==============================================================================
  155.  
  156.  
  157. #pragma segment QDGXShape
  158.  
  159.  
  160. static void
  161. ClearGXError( )
  162. {
  163.     GXGetGraphicsError(kODNULL);
  164.     // GX error status is cleared after asking for errors.
  165. }
  166.  
  167.  
  168. static void
  169. ThrowIfGXError( )
  170. {
  171.     gxGraphicsError err = GXGetGraphicsError(kODNULL);    // Get latest graphics error
  172.     if( err )
  173.         THROW(err,"QuickDraw GX error");
  174. }
  175.  
  176.  
  177. static void
  178. ThrowIfFirstGXError( )
  179. {
  180.     gxGraphicsError err;
  181.     (void) GXGetGraphicsError(&err);            // Get first error, not last
  182.     if( err )
  183.         THROW(err,"QuickDraw GX error");
  184. }
  185.  
  186.  
  187. /******************************************************************************/
  188. //**    ALLOCATION
  189. /******************************************************************************/
  190.  
  191.  
  192. ODPolygon::ODPolygon( )
  193.     :_maximum(0),
  194.      _length(0),
  195.      _buf(kODNULL)
  196. {
  197. }
  198.  
  199.  
  200. #if ODDebug
  201. ODPolygon::~ODPolygon( )
  202. {
  203.     // To help catch double-deletes of ODPolygon structures!
  204.     _buf = (ODPolygonData*)0xDDDDDDDD;
  205.     _length = _maximum = 0xDDDDDDDD;
  206. }
  207. #endif
  208.  
  209.  
  210. void
  211. ODPolygon::Delete( )
  212. {
  213.     ODDisposePtr(_buf);
  214.     delete this;
  215. }
  216.  
  217.  
  218. void
  219. ODPolygon::Clear( )
  220. {
  221.     ODDisposePtr(_buf);
  222.     _buf = kODNULL;
  223.     _length = _maximum = 0;
  224. }
  225.  
  226.  
  227. static ODULong
  228. CalcDataSize( ODSLong nVertices )
  229. {
  230.     if( nVertices==0 )
  231.         return 0;
  232.     else
  233.         return offsetof(ODPolygonData,firstContour.vertex[nVertices]);
  234. }
  235.  
  236.  
  237. void
  238. ODPolygon::Realloc( ODULong dataSize )
  239. {
  240.     if( _buf!=kODNULL && dataSize>=_length && dataSize<=_maximum )
  241.         _length = dataSize;
  242.     else {
  243.         ODPtr newData;
  244.         if( dataSize!=0 )
  245.             newData = ODNewPtr(dataSize, kDefaultHeapID);
  246.         ODDisposePtr(_buf);
  247.         if( dataSize!=0 )
  248.             _buf = (ODPolygonData*)newData;
  249.         else
  250.             _buf = kODNULL;
  251.         _length = _maximum = dataSize;
  252.     }
  253. }
  254.  
  255.  
  256. void
  257. ODPolygon::SetData( const ODPolygonData *data )
  258. {
  259.     _length = sizeof(ODULong) * (1+data->nContours);
  260.     const ODContour *c = &data->firstContour;
  261.     for( ODULong i=data->nContours; i!=0; i-- ) {
  262.         _length += c->nVertices * sizeof(ODPoint);
  263.         c = c->NextContour();
  264.     }
  265.     
  266.     ODDisposePtr(_buf);
  267.     _buf = (ODPolygonData*)data;
  268.     _maximum = _length;
  269. }
  270.  
  271.  
  272. ODPolygon*
  273. ODPolygon::SetNVertices( ODSLong nVertices )
  274. {
  275.     ASSERT(nVertices>=0,kODErrValueOutOfRange);
  276.     
  277.     this->Realloc(CalcDataSize(nVertices));
  278.     if( nVertices>0 ) {
  279.         _buf->nContours = 1;
  280.         _buf->firstContour.nVertices = nVertices;
  281.     }
  282.     return this;
  283. }
  284.  
  285.  
  286. ODPolygon*
  287. ODPolygon::SetVertices( ODSLong nVertices, const ODPoint *vertices )
  288. {
  289.     ASSERT(nVertices>=0,kODErrValueOutOfRange);
  290.     ASSERT(vertices!=kODNULL,kODErrIllegalNullInput);
  291.     
  292.     this->SetNVertices(nVertices);
  293.     if( nVertices>0 )
  294.         ODBlockMove( (void *) vertices, _buf->firstContour.vertex, nVertices*sizeof(ODPoint) );
  295.     return this;
  296. }
  297.  
  298.  
  299. ODPolygon*
  300. ODPolygon::SetContours( ODSLong nContours, const ODSLong *contourVertices )
  301. {
  302.     ASSERT(nContours>=0,kODErrValueOutOfRange);
  303.     if( nContours==0 )
  304.         return this->SetNVertices(0);
  305.     else {
  306.         ASSERT(contourVertices!=kODNULL,kODErrIllegalNullInput);
  307.         ODULong totalVertices = 0;
  308.         ODSLong i;
  309.         for( i=nContours-1; i>=0; i-- )
  310.             totalVertices += contourVertices[i];
  311.         this->Realloc( offsetof(ODPolygonData,firstContour)
  312.                      + offsetof(ODContour,vertex[0]) * nContours
  313.                      + sizeof(ODPoint)*totalVertices );
  314.         _buf->nContours = nContours;
  315.         ODContour *cont = this->FirstContour();
  316.         for( i=0; i<nContours; i++ ) {
  317.             cont->nVertices = contourVertices[i];
  318.             cont = cont->NextContour();
  319.         }
  320.         return this;
  321.     }
  322. }
  323.  
  324.  
  325. ODPolygon*
  326. ODPolygon::SetRect( const ODRect &r )
  327. {
  328.     if( r.IsEmpty() )
  329.         return this->SetNVertices(0);
  330.     else {
  331.         this->SetNVertices(4);
  332.         _buf->firstContour.vertex[0] = r.TopLeft();
  333.         _buf->firstContour.vertex[1].Set(r.right,r.top);
  334.         _buf->firstContour.vertex[2] = r.BotRight();
  335.         _buf->firstContour.vertex[3].Set(r.left,r.bottom);
  336.     }
  337.     return this;
  338. }
  339.  
  340.  
  341. ODPolygon*
  342. ODPolygon::CopyFrom( const ODPolygon &poly )
  343. {
  344.     if( poly._buf != _buf ) {
  345.         ODULong size = poly.GetDataSize();
  346.         this->Realloc(size);
  347.         ODBlockMove(poly.GetData(),_buf,size);
  348.     }
  349.     return this;
  350. }
  351.  
  352.  
  353. ODPolygon*
  354. ODPolygon::MoveFrom( ODPolygon &poly )
  355. {
  356.     if( poly._buf != _buf ) {
  357.         ODDisposePtr(_buf);
  358.         _buf = poly._buf;
  359.         _length = poly._length;
  360.         _maximum = poly._maximum;
  361.     }
  362.     if( &poly._buf != &_buf ) {            // Don't clear poly if it's myself!
  363.         poly._buf = kODNULL;
  364.         poly._length = poly._maximum = 0;
  365.     }
  366.     return this;
  367. }
  368.  
  369.  
  370.  
  371. #ifdef _PLATFORM_MACINTOSH_
  372. #pragma segment ODGXShape
  373.  
  374. ODPolygon*
  375. ODPolygon::CopyFrom( gxShape shape )
  376. {
  377.     ClearGXError();
  378.     TempGXShape copiedShape = GXCopyToShape(kODNULL,shape);
  379.     GXPrimitiveShape(copiedShape);
  380.     GXSimplifyShape(copiedShape);
  381.     GXSetShapeType(copiedShape,gxPolygonType);
  382.     ThrowIfFirstGXError();
  383.     
  384.     ODULong size = GXGetPolygonParts(copiedShape, 1,gxSelectToEnd, kODNULL);
  385.     ThrowIfGXError();
  386.     this->Realloc(size);
  387.     GXGetPolygonParts(copiedShape, 1,gxSelectToEnd, (gxPolygons*)_buf);
  388.     ThrowIfGXError();
  389.     
  390.     return this;
  391. }
  392. #pragma segment ODShape
  393. #endif
  394.  
  395.  
  396. ODPolygon*
  397. ODPolygon::ReadFrom( Environment *ev, ODStorageUnit *su )
  398. {
  399.  
  400.     if( !su->Exists(ev,kODNULL,kODPolygon,kODPosUndefined) ) {
  401.         this->Clear();
  402.     } else {
  403.         ODPropertyName propName = su->GetProperty(ev);
  404.         ODGetPolygonProp(ev, su, propName, kODPolygon, this);
  405.         ODDisposePtr((ODPtr) propName);
  406.     }
  407.  
  408.     return this;
  409. }
  410.  
  411.  
  412. ODPolygon*
  413. ODPolygon::WriteTo( Environment *ev, ODStorageUnit *su )  const
  414. {
  415.     ODPropertyName propName = su->GetProperty(ev);
  416.     ODSetPolygonProp(ev, su, propName, kODPolygon, this);
  417.     ODDisposePtr((ODPtr) propName);
  418.     
  419.     return (ODPolygon*)this;
  420. }
  421.  
  422.  
  423. /******************************************************************************/
  424. //**    POLYGON STUFF
  425. /******************************************************************************/
  426.  
  427.  
  428. ODSLong
  429. ODPolygon::GetNContours( )  const
  430. {
  431.     return _length>0 ?_buf->nContours :0;
  432. }
  433.  
  434.  
  435. const ODContour*
  436. ODPolygon::FirstContour( )  const
  437. {
  438.     return _length>0 ?&_buf->firstContour :kODNULL;
  439. }
  440.  
  441.  
  442. ODContour*
  443. ODPolygon::FirstContour( )
  444. {
  445.     return _length>0 ?&_buf->firstContour :kODNULL;
  446. }
  447.  
  448.  
  449. ODPolygon*
  450. ODPolygon::Copy( ) const
  451. {
  452.     ODTempPolygonPtr poly = new ODPolygon;
  453.     poly->CopyFrom(*this);
  454.     return poly.DontDelete();
  455. }
  456.  
  457.  
  458. void
  459. ODPolygon::ComputeBoundingBox( ODRect *bbox ) const
  460. {
  461.     ASSERT(bbox!=kODNULL,kODErrIllegalNullInput);
  462.     
  463.     if( _buf==kODNULL || _buf->nContours <= 0 ) {
  464.         bbox->Clear();
  465.         return;
  466.     }
  467.     
  468.     // Start bbox out as maximally empty:
  469.     bbox->left    = bbox->top        =  kMaxLong;
  470.     bbox->right = bbox->bottom    = -kMaxLong;
  471.     
  472.     const ODContour *c = this->FirstContour();
  473.     for( ODSLong i=this->GetNContours(); i>0; i-- ) {
  474.         ODPoint *pt = (ODPoint*)c->vertex;
  475.         for( ODSLong v=c->nVertices; v>0; v--,pt++ ) {
  476.             if( pt->x < bbox->left )    bbox->left    = pt->x;
  477.             if( pt->x > bbox->right )    bbox->right    = pt->x;
  478.             if( pt->y < bbox->top )        bbox->top    = pt->y;
  479.             if( pt->y > bbox->bottom )    bbox->bottom= pt->y;
  480.         }
  481.         if( i>1 )
  482.             c = c->NextContour();
  483.     }
  484. }
  485.  
  486.  
  487. ODBoolean
  488. ODContour::operator== ( const ODContour &cont ) const
  489. {
  490.     /*    This test is complicated by the fact that the two contours might have the
  491.         same points, but out of phase. Therefore we have to compare the points
  492.         in sequence, once per possible phase difference.  */
  493.     
  494.     ODSLong nv = this->nVertices;
  495.     if( nv != cont.nVertices )
  496.         return kODFalse;
  497.     
  498.     for( ODSLong phase=0; phase<nv; phase++ ) {
  499.         const ODPoint *p0 = &this->vertex[0];
  500.         const ODPoint *p1 = &cont.vertex[phase];
  501.         ODSLong i;
  502.         for( i=nVertices; i>0; i-- ) {
  503.             if( i==phase )
  504.                 p1 = &cont.vertex[0];
  505.             if( ! (p0++)->ApproxEquals(*p1++) )        // Coords may differ very slightly
  506.                 break;
  507.         }
  508.         if( i==0 )
  509.             return kODTrue;
  510.     }
  511.     return kODFalse;
  512. }
  513.  
  514.  
  515. Boolean
  516. ODPolygon::operator== ( ODPolygon &poly ) const
  517. {
  518.     /*    This test is complicated by the fact that the two polygons may not have their
  519.         contours in the same order. Our approach is to step through my contours in
  520.         order, trying to match each to a unique contour in the target. To ensure
  521.         uniqueness, the sign of the nVertices field in a target contour is flipped
  522.         after it's matched.  */
  523.     
  524.     if( this->GetNContours() != poly.GetNContours() )
  525.         return kODFalse;
  526.     if( &poly == this )
  527.         return kODTrue;
  528.     
  529.     ODBoolean result = kODTrue;
  530.     const ODContour * c = this->FirstContour();
  531.     ODContour *pc;
  532.     
  533.     ODSLong i;
  534.     for( i=this->GetNContours(); i>0; i-- ) {
  535.         pc = poly.FirstContour();
  536.         ODSLong j;
  537.         for( j=poly.GetNContours(); j>0; j-- ) {
  538.             if( pc->nVertices>0 && *c==*pc ) {        // Compare contours!
  539.                 pc->nVertices = -pc->nVertices;        // Use sign bit as a flag (yech)
  540.                 break;
  541.             }
  542.             if( j>1 )
  543.                 pc = pc->NextContour();
  544.         }
  545.         if( j<=0 ) {
  546.             result = kODFalse;                    // No match for contour
  547.             break;
  548.         }
  549.  
  550.         if( i>1 )
  551.             c = c->NextContour();
  552.     }
  553.  
  554.     // Now that we know, clear all the sign bits:
  555.     pc = poly.FirstContour();
  556.     for( i=poly.GetNContours(); i>0; i-- ) {
  557.         if( pc->nVertices<0 )
  558.             pc->nVertices = -pc->nVertices;
  559.         pc = pc->NextContour();
  560.     }
  561.     return result;
  562. }
  563.  
  564.  
  565. Boolean
  566. ODPolygon::IsEmpty( ) const
  567. {
  568.     // FIX: This is not very smart. It will probably be necessary to compute the area
  569.     // of each contour...
  570.     
  571.     return _buf==kODNULL || _buf->nContours==0;
  572. }
  573.  
  574.  
  575. Boolean
  576. ODPolygon::IsRectangular( ) const
  577. {
  578.     return _buf==kODNULL || _buf->nContours==0 ||
  579.             (_buf->nContours==1  && _buf->firstContour.IsRectangular());
  580. }
  581.  
  582.  
  583. Boolean
  584. ODPolygon::AsRectangle( ODRect *r ) const
  585. {
  586.     if( _buf==kODNULL || _buf->nContours==0 ) {
  587.         r->Clear();
  588.         return kODTrue;
  589.     } else if( _buf->nContours==1 )
  590.         return _buf->firstContour.AsRectangle(r);
  591.     else
  592.         return kODFalse;
  593. }
  594.  
  595.  
  596. Boolean
  597. ODContour::IsRectangular( ) const
  598. {
  599.     if( nVertices != 4 )
  600.         return kODFalse;
  601.     else if( vertex[0].x == vertex[1].x )            // 1st edge is vertical
  602.         return vertex[1].y==vertex[2].y
  603.             && vertex[2].x==vertex[3].x
  604.             && vertex[3].y==vertex[0].y;
  605.     else if( vertex[0].y == vertex[1].y )            // 1st edge is horizontal
  606.         return vertex[1].x==vertex[2].x
  607.             && vertex[2].y==vertex[3].y
  608.             && vertex[3].x==vertex[0].x;
  609.     else
  610.         return kODFalse;
  611. }
  612.  
  613.  
  614. Boolean
  615. ODContour::AsRectangle( ODRect *r ) const
  616. {
  617.     ASSERT(r!=kODNULL,kODErrIllegalNullInput);
  618.     
  619.     if( this->IsRectangular() ) {
  620.         ODRect r2(vertex[0],vertex[2]);            // C'tor properly orders the coords
  621.         *r = r2;
  622.         return kODTrue;
  623.     } else
  624.         return kODFalse;
  625. }
  626.  
  627.  
  628. /******************************************************************************/
  629. //**    REGION CONVERSION
  630. /******************************************************************************/
  631.  
  632.  
  633. ODBoolean
  634. ODContour::HasExactRegion( ) const
  635. {
  636.     const ODPoint *b = &vertex[0];
  637.     for( ODSLong i=nVertices; i>=0; i-- ) {
  638.         const ODPoint *a = &vertex[i];
  639.         if( (a->x & 0xFFFF) || (a->y & 0xFFFF) )
  640.             return kODFalse;                        // Non-integer coordinates
  641.         if( a->x!=b->x && a->y!=b->y )
  642.             return kODFalse;                        // Diagonal line
  643.         b = a;
  644.     }
  645.     return kODTrue;
  646. }
  647.  
  648.  
  649. ODBoolean
  650. ODPolygon::HasExactRegion( ) const
  651. {
  652.     const ODContour *c = this->FirstContour();
  653.     for( long i=this->GetNContours(); i>0; i-- ) {
  654.         if( !c->HasExactRegion() )
  655.             return kODFalse;
  656.         if( i>1 )
  657.             c = c->NextContour();
  658.     }
  659.     return kODTrue;
  660. }
  661.  
  662.  
  663. #ifdef _PLATFORM_MACINTOSH_
  664. PolyHandle
  665. ODContour::AsQDPolygon( ) const
  666. {
  667.     ODSLong size = (sizeof(short)+sizeof(Rect)+sizeof(Point)) + nVertices*sizeof(Point);
  668.     if( size > 32767 )
  669.         THROW(kODErrShapeTooComplex);
  670.     PolyHandle p = (PolyHandle) ODNewHandle(size);
  671.     (**p).polySize = (short)size;
  672.     Rect &bbox = (**p).polyBBox;
  673.     SetRect(&bbox,32767,32767,-32767,-32767);
  674.     
  675.     const ODPoint *src = &vertex[0];
  676.     Point *dst = &(**p).polyPoints[0];
  677.     for( ODSLong i=nVertices; i>0; i-- ) {
  678.         *dst = src->AsQDPoint();
  679.         if( dst->h < bbox.left  )    bbox.left  = dst->h;
  680.         if( dst->v < bbox.top   )    bbox.top   = dst->v;
  681.         if( dst->h > bbox.right )    bbox.right = dst->h;
  682.         if( dst->v > bbox.bottom)    bbox.bottom= dst->v;
  683.         src++;
  684.         dst++;
  685.     }
  686.     *dst = vertex[0].AsQDPoint();    // QD makes us repeat the 1st pt at the end
  687.     
  688.     return p;
  689. }
  690. #endif
  691.  
  692.  
  693. #ifdef _PLATFORM_MACINTOSH_
  694. RgnHandle
  695. ODPolygon::AsQDRegion( ) const
  696. {
  697.     // NOTE: This method will not work properly for self-intersecting polygons!
  698.     // QuickDraw uses even-odd filling, while OpenDoc uses winding-number.
  699.     
  700.     if( !this->HasData() )
  701.         return ODNewRgn();
  702.  
  703.     GrafPtr port, myPort;
  704.  
  705.     // Make sure we have a real port to work with:
  706.     GetPort(&port);
  707.     if( FrontWindow() ) {
  708.         SetPort(FrontWindow());
  709.         myPort = kODNULL;
  710.     } else {
  711.         myPort = new GrafPort;
  712.         OpenPort(myPort);
  713.     }
  714.     
  715.     RgnHandle rgn = ODNewRgn();
  716.     
  717.     OpenRgn();
  718.     TRY{
  719.         PolyHandle poly;
  720.         const ODContour *cont = this->FirstContour();
  721.         for( ODSLong i=_buf->nContours; i>0; i-- ) {
  722.             poly = cont->AsQDPolygon();
  723.             FramePoly(poly);
  724.             KillPoly(poly);
  725.             cont = cont->NextContour();
  726.         }
  727.     }CATCH_ALL{
  728.         CloseRgn(rgn);
  729.         DisposeRgn(rgn);
  730.         SetPort(port);
  731.         if( myPort ) {
  732.             ClosePort(myPort);
  733.             delete myPort;
  734.         }
  735.         RERAISE;
  736.     }ENDTRY
  737.     
  738.     CloseRgn(rgn);
  739.     
  740.     SetPort(port);
  741.     if( myPort ) {
  742.         ClosePort(myPort);
  743.         delete myPort;
  744.     }
  745.     return rgn;
  746. }
  747. #endif
  748.  
  749.  
  750. #ifdef _PLATFORM_MACINTOSH_
  751. gxShape
  752. ODPolygon::AsGXShape( ) const
  753. {
  754.     gxShape shape;
  755.     if( this->HasData() ) {
  756.         shape = GXNewPolygons( (gxPolygons*)this->GetData() );
  757.         GXSetShapeFill(shape,gxWindingFill);
  758.     } else
  759.         shape = GXNewShape(gxEmptyType);
  760.     
  761.     ThrowIfFirstGXError();
  762.     return shape;
  763. }
  764. #endif
  765.  
  766.  
  767. void
  768. ODPolygon::Transform( Environment *ev, ODTransform *xform )
  769. {
  770.     if( this->HasData() ) {
  771.         ODContour *c = &_buf->firstContour;
  772.         for( ODSLong i=_buf->nContours; i>0; i-- ) {
  773.             ODPoint *pt = c->vertex;
  774.             for( ODSLong v=c->nVertices; v>0; v--, pt++ )
  775.                 xform->TransformPoint(ev,pt);
  776.             if( i>1 )
  777.                 c = c->NextContour();
  778.         }
  779.     }
  780. }
  781.  
  782.  
  783. /******************************************************************************/
  784. //**    CONTAINMENT TEST
  785. /******************************************************************************/
  786.  
  787.  
  788. //------------------------------------------------------------------------------
  789. // ODPolygon::Contains
  790. //
  791. // Does a polygon contain a point?
  792. // We determine this by drawing a ray from the point to the right towards
  793. // infinity, and finding the polygon edges that intersect this ray. For each
  794. // such edge, count it as 1 if its y value is increasing, -1 if decreasing.
  795. // The sum of these values is 0 if the point is outside the polygon.
  796. //------------------------------------------------------------------------------
  797.  
  798. ODSLong
  799. ODPolygon::Contains( ODPoint point ) const
  800. {
  801.     if( !this->HasData() )
  802.         return kODFalse;
  803.  
  804.     ODSLong count = 0;
  805.     const ODPoint *pp1, *pp2;
  806.     ODPoint p1, p2;
  807.     ODPoint ray = point;
  808.     
  809.     for( PolyEdgeIterator polyIter (this); polyIter.IsNotComplete(); polyIter.Next() ) {
  810.         polyIter.CurrentEdge(pp1,pp2);
  811.         p1 = *pp1;
  812.         p2 = *pp2;
  813.         
  814.         if( p1.y==p2.y ) {                                            // Horizontal line: ignore
  815.             if( p1.y==point.y && InRange(point.x, p1.x,p2.x) ) {    // unless point is on it
  816.                 return 0;
  817.             }
  818.         } else {
  819.             ray.x = Max(p1.x,p2.x);
  820.             ODPoint sect;
  821.             if( ray.x >= point.x )
  822.                 if( IntersectSegments(p1,p2, point,ray, §) ) {
  823.                     if( WithinEpsilon(point.x,sect.x) && WithinEpsilon(point.y,sect.y) ) {
  824.                         return 0;
  825.                     }
  826.                     if( p2.y > p1.y )
  827.                         count++;
  828.                     else
  829.                         count--;
  830.                 }
  831.         }
  832.     }
  833.     
  834.     return count;
  835. }
  836.  
  837.  
  838. /******************************************************************************/
  839. //**    POLYGON EDGE ITERATOR
  840. /******************************************************************************/
  841.  
  842.  
  843. PolyEdgeIterator::PolyEdgeIterator( const ODPolygon *poly )
  844.     :fPoly (poly)
  845. {
  846.     fCurContour = poly->FirstContour();
  847.     fCurContourIndex = 0;
  848.     fCurVertex = 0;
  849. }
  850.  
  851.  
  852. void
  853. PolyEdgeIterator::CurrentEdge( const ODPoint* &v1, const ODPoint* &v2 )
  854. {
  855.     v1 = &fCurContour->vertex[fCurVertex];
  856.     if( fCurVertex+1 < fCurContour->nVertices )
  857.         v2 = v1+1;
  858.     else
  859.         v2 = &fCurContour->vertex[0];
  860. }
  861.  
  862.  
  863. Boolean
  864. PolyEdgeIterator::Next( )
  865. {
  866.     if( !fCurContour )                                    // Was already finished
  867.         return false;
  868.     if( ++fCurVertex >= fCurContour->nVertices )        // Next vertex; if past contour:
  869.         if( ++fCurContourIndex >= fPoly->GetNContours() ) {        // Next contour; if past end:
  870.             fCurContour = kODNULL;
  871.             return false;                                        //...we're done.
  872.         } else {
  873.             fCurContour = fCurContour->NextContour();            // Else go to start of contour
  874.             fCurVertex = 0;
  875.         }
  876.     return kODTrue;
  877. }
  878.  
  879.  
  880. Boolean
  881. PolyEdgeIterator::IsNotComplete( )
  882. {
  883.     return fCurContour!=kODNULL;
  884. }
  885.